#include "PerdoVisitor.h"
#include <iostream>
#include <sstream>
#include <fstream>

#include "Char.h"
#include "Command.h"
#include "Id.h"
#include "Index.h"
#include "Number.h"
#include "StatementList.h"
#include "String.h"

#include "Add.h"
#include "Sub.h"
#include "Mul.h"
#include "Div.h"
#include "Mod.h"
#include "Neg.h"
#include "Equ.h"

#include "DoubleEqual.h"
#include "NotEqual.h"
#include "Less.h"
#include "LessEqual.h"
#include "Greater.h"
#include "GreaterEqual.h"
#include "And.h"
#include "Or.h"

#include "While.h"
#include "If.h"

using namespace std;

int PerdoVisitor::RipAS(string s)
{
	stringstream ss(s);
	char c;
	int i;
	ss >> c;
	ss >> i;
	return i;
}

PerdoVisitor::PerdoVisitor(SymbolTable * Sym, ostream * Out):
	sym(Sym), out(Out), whileCount(0), ifCount(0)
{
	*out << "main:" << endl;
	// This works on the assumption that the IntPerdoVisitor has previously been accepted.
	*out << "store " << sym->getPeak() << " 0" << endl;
}

void PerdoVisitor::visitDoubleEqual( DoubleEqual* DE )
{
	DE->getLeft()->accept(*this);
	DE->getRight()->accept(*this);

	int right = stk.top();
	stk.pop();
	int left = stk.top();
	stk.pop();

	*out << "# Compare(==)" << endl;
	*out << "load " << left << " regA" << endl;
	*out << "load " << right << " regB" << endl;
	*out << "if_equ regA regB regC" << endl;
	*out << "nop" << endl;
	int mempos = RipAS(sym->useNextScalar('n'));
	*out << "store regC " << mempos << endl;

	stk.push(mempos);
}
void PerdoVisitor::visitGreater( Greater* GR )
{
	GR->getLeft()->accept(*this);
	GR->getRight()->accept(*this);

	int right = stk.top();
	stk.pop();
	int left = stk.top();
	stk.pop();

	*out << "# Compare(>)" << endl;
	*out << "load " << left << " regA" << endl;
	*out << "load " << right << " regB" << endl;
	*out << "if_gtr regA regB regC" << endl;
	*out << "nop" << endl;
	int mempos = RipAS(sym->useNextScalar('n'));
	*out << "store regC " << mempos << endl;

	stk.push(mempos);
}
void PerdoVisitor::visitLess( Less* LS )
{
	LS->getLeft()->accept(*this);
	LS->getRight()->accept(*this);

	int right = stk.top();
	stk.pop();
	int left = stk.top();
	stk.pop();

	*out << "# Compare(<)" << endl;
	*out << "load " << left << " regA" << endl;
	*out << "load " << right << " regB" << endl;
	*out << "if_less regA regB regC" << endl;
	*out << "nop" << endl;
	int mempos = RipAS(sym->useNextScalar('n'));
	*out << "store regC " << mempos << endl;

	stk.push(mempos);
}
void PerdoVisitor::visitGreaterEqual( GreaterEqual* GE )
{
	GE->getLeft()->accept(*this);
	GE->getRight()->accept(*this);

	int right = stk.top();
	stk.pop();
	int left = stk.top();
	stk.pop();

	*out << "# Compare(>=)" << endl;
	*out << "load " << left << " regA" << endl;
	*out << "load " << right << " regB" << endl;
	*out << "if_gtr_equ regA regB regC" << endl;
	*out << "nop" << endl;
	int mempos = RipAS(sym->useNextScalar('n'));
	*out << "store regC " << mempos << endl;

	stk.push(mempos);
}
void PerdoVisitor::visitLessEqual( LessEqual* LE )
{
	LE->getLeft()->accept(*this);
	LE->getRight()->accept(*this);

	int right = stk.top();
	stk.pop();
	int left = stk.top();
	stk.pop();

	*out << "# Compare(<=)" << endl;
	*out << "load " << left << " regA" << endl;
	*out << "load " << right << " regB" << endl;
	*out << "if_less_equ regA regB regC" << endl;
	*out << "nop" << endl;
	int mempos = RipAS(sym->useNextScalar('n'));
	*out << "store regC " << mempos << endl;

	stk.push(mempos);
}
void PerdoVisitor::visitNotEqual( NotEqual* NE )
{
	NE->getLeft()->accept(*this);
	NE->getRight()->accept(*this);

	int right = stk.top();
	stk.pop();
	int left = stk.top();
	stk.pop();

	*out << "# Compare(!=)" << endl;
	*out << "load " << left << " regA" << endl;
	*out << "load " << right << " regB" << endl;
	*out << "if_n_equ regA regB regC" << endl;
	*out << "nop" << endl;
	int mempos = RipAS(sym->useNextScalar('n'));
	*out << "store regC " << mempos << endl;

	stk.push(mempos);
}
void PerdoVisitor::visitAnd( And* AND )
{
	AND->getLeft()->accept(*this);
	AND->getRight()->accept(*this);

	int right = stk.top();
	stk.pop();
	int left = stk.top();
	stk.pop();

	*out << "# Compare(&&)" << endl;
	*out << "load " << left << " regA" << endl;
	*out << "load " << right << " regB" << endl;
	*out << "if_n_equ regA 0 regC" << endl;
	*out << "if_n_equ regB 0 regC" << endl;
	*out << "nop" << endl;

	int mempos = RipAS(sym->useNextScalar('n'));
	*out << "store regC " << mempos << endl;

	stk.push(mempos);
}
void PerdoVisitor::visitOr( Or* OR )
{
	OR->getLeft()->accept(*this);
	OR->getRight()->accept(*this);

	int right = stk.top();
	stk.pop();
	int left = stk.top();
	stk.pop();

	*out << "# Compare(||)" << endl;
	*out << "load " << left << " regA" << endl;
	*out << "load " << right << " regB" << endl;
	*out << "if_n_equ regA 0 regC" << endl;
	*out << "if_equ regC 0 regD" << endl;
	*out << "if_n_equ regB 0 regC" << endl;
	*out << "nop" << endl;

	int mempos = RipAS(sym->useNextScalar('n'));
	*out << "store regC " << mempos << endl;

	stk.push(mempos);
}
void PerdoVisitor::visitWhile( While* WL )
{
	incWhile();
	string whileX = getWhile();
	string done_whileX = getDoneWhile();

	*out << "# While (really)" << endl;
	*out << whileX << ":" << endl;
	WL->getCondition()->accept(*this);
	*out << "load " << stk.top() << " regA" << endl;
	*out << "if_equ regA 0 regB" << endl;
	*out << "jump " << done_whileX << endl;
	WL->getBlock()->accept(*this);
	*out << "jump " << whileX << endl;
	*out << done_whileX << ":" << endl;
}
void PerdoVisitor::visitIf( If* IF )
{
	incIf();
	string ifX = getIf();
	string done_ifX = getDoneIf();
	string elseX = getElse();

	*out << ifX << ":" << endl;
	IF->getCondition()->accept(*this);
	*out << "load " << stk.top() << " regA" << endl;
	stk.pop();
	*out << "if_equ regA 0 regB" << endl;
	*out << "jump " << elseX << endl;
	(*IF->getBlocks().begin())->accept(*this);
	*out << "jump " << done_ifX << endl;
	*out << elseX << ":" << endl;
	if( IF->getBlocks().size() > 1 )
	{
		(*(IF->getBlocks().end()-1))->accept(*this);
	}
	*out << done_ifX << ":" << endl;
}

void PerdoVisitor::visitNumber( Number* NUM )
{
	*out << "# Store a literal number to temporary mem pos" << endl;
	int mempos = RipAS(sym->useNextScalar('n'));
	*out << "val_copy " << NUM->getValue() << " regA" << endl;
	*out << "store regA " << mempos << endl;
	stk.push(mempos);
}

void PerdoVisitor::visitIndex( Index* INDEX )
{
	INDEX->getIdentifier()->accept(*this);
	INDEX->getOffset()->accept(*this);

	if( INDEX->isLeft() )
	{
	}
	else{	// Print out array_get_index stuff
		int right = stk.top();
		stk.pop();
		int left = stk.top();
		stk.pop();
		//int reg = sym->useNextRegister();
		// Get the int ID of left so we can look it up in the symbol table
		stringstream ss;
		char temp;
		ss << left;
		int reg;
		ss >> temp >> reg;
		int mempos_value = RipAS(sym->useNextScalar(sym->GetType(reg)));
		ArrayGetIndex(left, right, mempos_value);
		stk.push(mempos_value);
	}
}

void PerdoVisitor::visitChar( Char* CHAR )
{
	*out << "# Store a literal char to temporary mem pos" << endl;
	int mempos = RipAS(sym->useNextScalar('c'));
	*out << "store " << CHAR->getValue() << " " << mempos << endl;
	stk.push(mempos);
}

void PerdoVisitor::visitString( String* STRING )
{
	int mempos_array = RipAS(sym->useNextArray('c'));
	string s = STRING->getValue();
	////////////////////////////////////////////////////////////////
	int mempos_size = RipAS(sym->useNextScalar('n'));
	*out << "val_copy " << s.size() << " regA" << endl;
	*out << "store regA " << mempos_size << endl;
	////////////////////////////////////////////////////////////////
	ArraySetSize(mempos_array, mempos_size);
	////////////////////////////////////////////////////////////////
	int mempos_index = RipAS(sym->useNextScalar('n'));
	int mempos_value = RipAS(sym->useNextScalar('c'));
	////////////////////////////////////////////////////////////////
	for( uint k = 0; k < s.size(); k++ )
	{
		*out << "val_copy " << k << " regA" << endl;
		*out << "store regA " << mempos_index << endl;
		*out << "val_copy '" << s[k] << "' regA" << endl;
		*out << "store regA " << mempos_value << endl;
		ArraySetIndex(mempos_array, mempos_index, mempos_value);
	}
	stk.push(mempos_array);
}

void PerdoVisitor::visitId( Id* ID )
{
	int id = ID->getId();

	if( !sym->ValidId(id) )
	{
		cerr << "Something very bad happened in PerdoVisitor visitId()" << endl;
		exit(1);
	}

	// Check if it is an array
	if( sym->GetVType(id) == 'a' )
	{
		// id is actually a pointer - initialize it
		*out << "# Initialize new array" << endl;
		// Load next free memory regA
		*out << "load 0 regA" << endl;
		// Store address in regA to memory position id
		*out << "store regA " << id << endl;
		// Store value of 0 into memory postion represented by regA
		*out << "store 0 regA" << endl;
		// Increment regA so it points to next available memory
		*out << "add regA 1 regA" << endl;
		// Store value in regA to memory position zero
		*out << "store regA 0" << endl;
	}

	stk.push(id);
}

void PerdoVisitor::visitStatementList( StatementList* SL )
{
	for( list<Node*>::const_iterator it = SL->getStatementList().begin(); it != SL->getStatementList().end(); it++ )
	{
		(*it)->accept(*this);
	}
}

void PerdoVisitor::visitCommand( Command* COMMAND )
{
	for( list<Node*>::const_reverse_iterator rit = COMMAND->getExprList().rbegin(); rit != COMMAND->getExprList().rend(); rit++ )
		(*rit)->accept(*this);

	string n = COMMAND->getName();
	if( n == "print" )
	{

		for( list<Node*>::const_iterator it = COMMAND->getExprList().begin(); it != COMMAND->getExprList().end(); it++ )
		{
			// Get the int ID# of stk.top() so we can look it up in the symbol table
			int var = stk.top();

			string output;
			//check to see if it is a number or a character
			if (sym->GetType(var) == 'n')
				output = "out_num ";
			else
				output = "out_char ";

			//check if it is an array or if it is a scalar
			if (sym->GetVType(var) == 's')
			{
				*out << "load " << var << " regA" << endl;
				*out << output << "regA" << endl;
			}
			else
			{
				incWhile();
				string whileX = getWhile();
				string done_whileX = getDoneWhile();

				*out << "# Print array" << endl;
				*out << "load " << var << " regA" << endl;
				*out << "load regA regB" << endl;
				*out << "add regA regB regB" << endl;
				*out << "add 1 regA regA" << endl;
				*out << whileX << ":" << endl;
				*out << "if_gtr regA regB regC" << endl;
				*out << "jump " << done_whileX << endl;
				*out << output << "regA" << endl;
				*out << "add 1 regA regA" << endl;
				*out << "jump " << whileX << endl;
				*out << done_whileX << ":" << endl;
			}
			// Get rid of thing we just printed
			stk.pop();
		}
		*out << "out_char '\\n'" << endl;
	}
	else if( n == "time" )
	{
		int mempos = RipAS(sym->useNextScalar('n'));
		*out << "time regA" << endl;
		*out << "store regA " << mempos << endl;
		stk.push(mempos);
	}
	else if( n == "random" )
	{
		int mempos = RipAS(sym->useNextScalar('n'));
		*out << "load " << stk.top() << " regA" << endl;
		stk.pop();
		*out << "random regA regB" << endl;
		*out << "store regB " << mempos << endl;
		stk.push(mempos);
	}
	else if (n == "size")
	{
		int mempos = RipAS(sym->useNextScalar('n'));
		// Load array pointer
		*out << "load " << stk.top() << " regA" << endl;
		stk.pop();
		// Load array size
		*out << "load regA regB" << endl;
		*out << "store regB " << mempos << endl;
		stk.push(mempos);
	}
	else if (n == "resize")
	{
		int newsize = stk.top();
		stk.pop();
		int array_id = stk.top();
		stk.pop();

		ArraySetSize(array_id, newsize);
	}
	else if (n == "zeros")
	{
		/*
		// Make counter
		string sTemp = sym->useNextScalar('n');
		*out << "val_copy 0 " << sTemp << endl;

		// Make variable to store conditional answer in
		string sTemp2 = sym->useNextScalar('n');

		// Make temp array
		string sTemp3 = sym->useNextArray('n');
		*out << "array_set_size " << sTemp3 << " " << stk.top() << endl;

		// Make while label
		string w = getNextWhileLabel();
		*out << w << ":" << endl;

		// Make condition
		*out << "if_equ " << stk.top() << " " << sTemp << " " << sTemp2 << endl;
		*out << "jump done_" << w << endl;

		// Write block for copying zeros
		// Increment counter
		*out << "array_set_index " << sTemp3 << " " << sTemp << " 0" << endl;
		*out << "add 1 " << sTemp << " " << sTemp << endl;

		// Make end while label
		*out << "jump " << w << endl;
		*out << "done_" << w << ":" << endl;
		stk.pop();
		stk.push(sTemp3);
		*/
	}
	/*
	else if( n == "set_rotate" )
	{
		//void set_rotate(number angle);
		//rotate src
		*out << "rotate " << stk.top() << endl;
	}
	else if( n == "get_rotate" )
	{
		//number get_rotate();
		//rotate_stat dest
		string sTemp = sym->useNextScalar('n');
		*out << "rotate_stat " << sTemp << endl;
		stk.push(sTemp);
	}
	else if( n == "set_move" )
	{
		//void set_move(number distance);
		//move src
		*out << "move " << stk.top() << endl;
	}
	else if( n == "get_move" )
	{
		//number get_move();
		//move_stat dest
		string sTemp = sym->useNextScalar('n');
		*out << "move_stat " << sTemp << endl;
		stk.push(sTemp);
	}
	else if( n == "set_shields" )
	{
		//void set_shields(number energy);
		//shields src
		*out << "shields " << stk.top() << endl;
	}
	else if( n == "get_shields" )
	{
		//number get_shields();
		//shield_stat dest
		string sTemp = sym->useNextScalar('n');
		*out << "shield_stat " << sTemp << endl;
		stk.push(sTemp);
	}
	else if( n == "fire" )
	{
		//void fire(number energy);
		//fire src
		*out << "fire " << stk.top() << endl;
	}
	else if( n == "get_energy" )
	{
		//number get_energy();
		//energy_stat dest
		string sTemp = sym->useNextScalar('n');
		*out << "energy_stat " << sTemp << endl;
		stk.push(sTemp);
	}
	else if( n == "scan_distance" )
	{
		//number scan_distance();
		//scan distance ID angle
		string tempDist = sym->useNextScalar('n');
		string tempID = sym->useNextScalar('n');
		string tempAngle = sym->useNextScalar('n');
		*out << "scan " << tempDist << " " << tempID << " " << tempAngle << endl;
		stk.push(tempDist);
	}
	else if( n == "scan_angle" )
	{
		//number scan_angle();
		//scan distance ID angle
		string tempDist = sym->useNextScalar('n');
		string tempID = sym->useNextScalar('n');
		string tempAngle = sym->useNextScalar('n');
		*out << "scan " << tempDist << " " << tempID << " " << tempAngle << endl;
		stk.push(tempAngle);
	}
	else if( n == "scan_id" )
	{
		//number scan_id();
		//scan distance ID angle
		string tempDist = sym->useNextScalar('n');
		string tempID = sym->useNextScalar('n');
		string tempAngle = sym->useNextScalar('n');
		*out << "scan " << tempDist << " " << tempID << " " << tempAngle << endl;
		stk.push(tempID);
	}
	*/
}

void PerdoVisitor::visitAdd( Add* ADD )
{
	ADD->getLeft()->accept(*this);
	ADD->getRight()->accept(*this);

	int right = stk.top();
	stk.pop();
	int left = stk.top();
	stk.pop();

	*out << "# Add operation" << endl;
	*out << "load " << left << " regA" << endl;
	*out << "load " << right << " regB" << endl;
	*out << "add regA regB regC" << endl;
	int mempos = RipAS(sym->useNextScalar('n'));
	*out << "store regC " << mempos << endl;

	stk.push(mempos);
}

void PerdoVisitor::visitSub( Sub* SUB )
{
	SUB->getLeft()->accept(*this);
	SUB->getRight()->accept(*this);

	int right = stk.top();
	stk.pop();
	int left = stk.top();
	stk.pop();

	*out << "# Sub operation" << endl;
	*out << "load " << left << " regA" << endl;
	*out << "load " << right << " regB" << endl;
	*out << "sub regA regB regC" << endl;
	int mempos = RipAS(sym->useNextScalar('n'));
	*out << "store regC " << mempos << endl;

	stk.push(mempos);
}

void PerdoVisitor::visitMul( Mul* MUL )
{
	MUL->getLeft()->accept(*this);
	MUL->getRight()->accept(*this);

	int right = stk.top();
	stk.pop();
	int left = stk.top();
	stk.pop();

	*out << "# Mul operation" << endl;
	*out << "load " << left << " regA" << endl;
	*out << "load " << right << " regB" << endl;
	*out << "mult regA regB regC" << endl;
	int mempos = RipAS(sym->useNextScalar('n'));
	*out << "store regC " << mempos << endl;

	stk.push(mempos);
}

void PerdoVisitor::visitDiv( Div* DIV )
{
	DIV->getLeft()->accept(*this);
	DIV->getRight()->accept(*this);

	int right = stk.top();
	stk.pop();
	int left = stk.top();
	stk.pop();

	*out << "# Div operation" << endl;
	*out << "load " << left << " regA" << endl;
	*out << "load " << right << " regB" << endl;
	*out << "div regA regB regC" << endl;
	int mempos = RipAS(sym->useNextScalar('n'));
	*out << "store regC " << mempos << endl;

	stk.push(mempos);
}

void PerdoVisitor::visitMod( Mod* MOD )
{
	MOD->getLeft()->accept(*this);
	MOD->getRight()->accept(*this);

	int right = stk.top();
	stk.pop();
	int left = stk.top();
	stk.pop();

	*out << "# Mod operation" << endl;
	*out << "load " << left << " regA" << endl;
	*out << "load " << right << " regB" << endl;
	*out << "mod regA regB regC" << endl;
	int mempos = RipAS(sym->useNextScalar('n'));
	*out << "store regC " << mempos << endl;

	stk.push(mempos);
}

void PerdoVisitor::visitEqu( Equ* EQU )
{
	//parent_is_equ = true;
	
	EQU->getLeft()->accept(*this);
	//parent_is_equ = false;
	EQU->getRight()->accept(*this);
	if(EQU->isLeft())
	{
		int source = stk.top();
		stk.pop();
		int offset = stk.top();
		stk.pop();
		int identifier = stk.top();
		stk.pop();
		ArraySetIndex(identifier, offset, source);
	}
	else
	{
		int src = stk.top();
		stk.pop();
		int dest = stk.top();
		stk.pop();

		if( sym->GetVType(dynamic_cast<Id*>(EQU->getLeft())->getId()) == 's' )
			*out << "mem_copy " << src << " " << dest << endl;
		else
			ArrayCopy(src, dest);
	}
}

void PerdoVisitor::visitNeg( Neg* NEG )
{
	NEG->getChild()->accept(*this);
	
	*out << "# Neg operation" << endl;
	*out << "load " << stk.top() << " regA" << endl;
	stk.pop();
	*out << "mult regA -1 regB" << endl;
	int mempos = RipAS(sym->useNextScalar('n'));
	*out << "store regB " << mempos << endl;

	stk.push(mempos);
}

// Set the size of a(array_id) to be the value stored in s(size_id)
// size_id is a memory position, just like array_id!
void PerdoVisitor::ArraySetSize(int array_id, int size_id)
{
	*out << "# Set array size" << endl;
	// Get next available memory position
	*out << "load 0 regA" << endl;
	// Load contents of mempory postion array_id
	*out << "load " << array_id << " regB" << endl;
	// Set pointer to point to new location
	*out << "store regA " << array_id << endl;
	// Load contents of memory position size_id
	*out << "load " << size_id << " regC" << endl;
	// Load old size
	*out << "load regB regD" << endl;
	// Create a new array (set its size)
	*out << "store regC regA" << endl;
	// Store the new available pos in the zero memory pos
	*out << "add regA regC regG" << endl;
	*out << "add regG 1 regG" << endl;
	*out << "store regG 0" << endl;
	// Move old array to new array
	*out << "val_copy 0 regE" << endl;
	incWhile();
	string whileX = getWhile();
	string done_whileX = getDoneWhile();
	*out << whileX << ":" << endl;
	*out << "add 1 regA regA" << endl;
	*out << "add 1 regB regB" << endl;
	*out << "add 1 regE regE" << endl;
	*out << "if_gtr regE regD regF" << endl;
	*out << "jump " << done_whileX << endl;
	*out << "mem_copy regB regA" << endl;
	*out << "jump " << whileX << endl;
	*out << done_whileX << ":" << endl;
}

// Get the size of a(array_id) and store it in s(size_id)
void PerdoVisitor::ArrayGetSize(int array_id, int size_id)
{
	*out << "# Get array size" << endl;
	// Load contents (address of array) of memory position array_id into regA
	*out << "load " << array_id << " regA" << endl;
	// Load contents (size) of mempory position regA into regB
	*out << "load regA regB" << endl;
	// Store contents (size) of regB into memory position size_id
	*out << "store regB " << size_id << endl;
}

// Set the s(index_id) index of a(array_id) to be the value s(value_id)
void PerdoVisitor::ArraySetIndex(int array_id, int index_id, int value_id)
{
	*out << "# Set array index" << endl;
	// Load the contents (address) of mempory position array_id into regA
	*out << "load " << array_id << " regA" << endl;
	// Load the contents (index) of memory position index_id into regB
	*out << "load " << index_id << " regB" << endl;
	// Add one to regA -- regA now holds the address of the array's first element
	*out << "add regA 1 regA" << endl;
	// Add regA and regB -- regA now holds the address of our desired element
	*out << "add regA regB regA" << endl;
	// Load the contents (valud to store) of memory position value_id into regC
	*out << "load " << value_id << " regC" << endl;
	// Store the regC to memory position regA
	*out << "store regC regA" << endl;
}

// Get the value at the s(index_id) index of a(array_id) and store it in s(value_id)
void PerdoVisitor::ArrayGetIndex(int array_id, int index_id, int value_id)
{
	*out << "# Get array index" << endl;
	// Load the contents (address) of mempory position array_id into regE
	*out << "load " << array_id << " regE" << endl;
	// Load the contents (index) of memory position index_id into regF
	*out << "load " << index_id << " regF" << endl;
	// Add one to regE -- regE now holds the address of the array's first element
	*out << "add regE 1 regE" << endl;
	// Add regE and regF -- regE now holds the address of our desired element
	*out << "add regE regF regE" << endl;
	// Load the contents of memory postion regE into regG
	*out << "load regE regG" << endl;
	// Store the contents of regG to memory position value_id
	*out << "store regG " << value_id << endl;
}

void PerdoVisitor::ArrayCopy(int src, int dest)
{
	*out << "# Array copy" << endl;
	// Get next available memory position
	*out << "load 0 regA" << endl;
	// Load contents of memory position src
	*out << "load " << src << " regB" << endl;
	// Load contents of memory position dest
	*out << "load " << dest << " regC" << endl;
	// Load the sizes of src and dest
	*out << "load regB regD" << endl;
	*out << "load regC regE" << endl;
	// See which array is smaller
	*out << "if_gtr_equ regE regD regF" << endl;
	incIf();
	// Jump to the "enough space" section
	*out << "jump " << getElse() << endl;
	// ------- Not enough space section -------
	// Update the dest pointer
	*out << "store regA " << dest << endl;
	*out << "val_copy regA regC" << endl;
	// Update next available memory position
	*out << "add regA 1 regA" << endl;
	*out << "add regA regD regA" << endl;
	*out << "store regA 0" << endl;
	// ------- Enough space section --------
	*out << getElse() << ":" << endl;
	// Copy src to dest
	*out << "add regB regD regE" << endl;
	incWhile();
	string whileX = getWhile();
	string done_whileX = getDoneWhile();
	*out << whileX << ":" << endl;
	*out << "if_gtr regB regE regF" << endl;
	*out << "jump " << done_whileX << endl;
	*out << "mem_copy regB regC" << endl;
	*out << "add 1 regB regB" << endl;
	*out << "add 1 regC regC" << endl;
	*out << "jump " << whileX << endl;
	*out << done_whileX << ":" << endl;
}

void PerdoVisitor::incWhile()
{ whileCount++; }

void PerdoVisitor::incIf()
{ ifCount++; }

std::string PerdoVisitor::getWhile()
{
	stringstream ss;
	ss << whileCount;
	return string("while") + ss.str();
}

std::string PerdoVisitor::getDoneWhile()
{
	stringstream ss;
	ss << whileCount;
	return string("done_while") + ss.str();
}

std::string PerdoVisitor::getIf()
{
	stringstream ss;
	ss << ifCount;
	return string("if") + ss.str();
}

std::string PerdoVisitor::getElse()
{
	stringstream ss;
	ss << ifCount;
	return string("else") + ss.str();
}

std::string PerdoVisitor::getDoneIf()
{
	stringstream ss;
	ss << ifCount;
	return string("done_if") + ss.str();
}

